﻿ #region Disclaimer/Info
 
 /////////////////////////////////////////////////////////////////////////////////////////////////
 //
 //   File:		ThemeFileResult.cs
 //   Website:		http://dexterblogengine.com/
 //   Authors:		http://dexterblogengine.com/About.ashx
 //   Rev:		1
 //   Created:		19/01/2011
 //   Last edit:		19/01/2011
 //   License:		GNU Library General Public License (LGPL)
 // 
 //   For updated news and information please visit http://dexterblogengine.com/
 //   Dexter is hosted to Codeplex at http://dexterblogengine.codeplex.com
 //   For any question contact info@dexterblogengine.com
 //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 #endregion

using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Web.Mvc;
using Dexter.Services;

namespace Dexter.Web.Mvc.Results {
	public class ThemeFileResult : ActionResult {
		static readonly string[] imagesExtensionAllowed = new[] {".jpg" , ".jpeg" , ".gif" , ".png" , ".bmp" , ".tiff" , ".ico"};
		static readonly string[] mediaExtensionAllowed = new[] {".swf" , ".xap"};
		static readonly string[] stylesExtensionAllowed = new[] {".css"};
		static readonly string[] scriptsExtensionAllowed = new[] {".js"};

		readonly string passedFileName;
		readonly IBlogTheme theme;

		/// <summary>
		/// 	Initializes a new instance of the <see cref = "ThemeFileResult" /> class.
		/// </summary>
		/// <param name = "passedFileName">Name of the passed file.</param>
		/// <param name = "currentTheme">The current theme.</param>
		public ThemeFileResult ( string passedFileName , IBlogTheme currentTheme ) {
			this.passedFileName = passedFileName;
			this.theme = currentTheme;
		}

		/// <summary>
		/// 	Enables processing of the result of an action method by a custom type that inherits from the <see cref = "T:System.Web.Mvc.ActionResult" /> class.
		/// </summary>
		/// <param name = "context">The context in which the result is executed. The context information includes the controller, HTTP content, request context, and route data.</param>
		public override void ExecuteResult ( ControllerContext context ) {
			string filePath;
			string fileExtension = Path.GetExtension ( passedFileName );

			if ( string.IsNullOrEmpty ( fileExtension ) ) {
				throw new HttpException ( 404 , "File Not Found." );
			}

			if ( imagesExtensionAllowed.Contains ( fileExtension ) ) {
				filePath = theme.GetImagePath ( passedFileName );
			}
			else if ( mediaExtensionAllowed.Contains ( fileExtension ) ) {
				filePath = theme.GetMediaPath ( passedFileName );
			}
			else if ( stylesExtensionAllowed.Contains ( fileExtension ) ) {
				filePath = theme.GetStylePath ( passedFileName );
			}
			else if ( scriptsExtensionAllowed.Contains ( fileExtension ) ) {
				filePath = theme.GetScriptPath ( passedFileName );
			}
			else {
				filePath = theme.GetFilePath ( passedFileName );
			}

			FileInfo fl = new FileInfo ( filePath );

			if ( !fl.Exists ) {
				throw new HttpException ( 404 , "File Not Found." );
			}

			var wrapper = new HttpContextWrapper ( HttpContext.Current );
			const int CACHE_DAYS = 7;

			context.HttpContext.Response.ContentType = fileExtension.GetMimeType (  );
			context.HttpContext.Response.ContentEncoding = Encoding.UTF8;

			context.HttpContext.Response.Cache.VaryByHeaders[ "Accept-Encoding" ] = true;
			context.HttpContext.Response.Cache.SetCacheability ( HttpCacheability.Public );
			context.HttpContext.Response.Cache.SetExpires ( DateTime.Now.AddDays ( CACHE_DAYS ) );
			context.HttpContext.Response.Cache.SetMaxAge ( new TimeSpan ( CACHE_DAYS , 0 , 0 , 0 ) );
			context.HttpContext.Response.Cache.SetRevalidation ( HttpCacheRevalidation.AllCaches );

			string etag = string.Concat ( "\"" , fl.LastWriteTime.GetHashCode ( ) , "\"" );
			string incomingEtag = wrapper.Request.Headers[ "If-None-Match" ];

			context.HttpContext.Response.Cache.SetETag ( etag );
			context.HttpContext.Response.Cache.SetCacheability ( HttpCacheability.Public );

			if ( String.Compare ( incomingEtag , etag ) == 0 ) {
				context.HttpContext.Response.Clear ( );
				context.HttpContext.Response.StatusCode = ( int ) HttpStatusCode.NotModified;
				context.HttpContext.Response.SuppressContent = true;
			}

			context.HttpContext.Response.AddFileDependency ( fl.FullName );
			context.HttpContext.Response.Cache.SetLastModifiedFromFileDependencies ( );
			context.HttpContext.Response.TransmitFile ( fl.FullName );
		}
	}
}
